package com.xlabs.client;

import java.util.List;

import com.google.gwt.core.client.GWT;
import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.event.dom.client.ClickHandler;
import com.google.gwt.user.client.rpc.AsyncCallback;
import com.google.gwt.user.client.ui.Button;
import com.google.gwt.user.client.ui.Composite;
import com.google.gwt.user.client.ui.Grid;
import com.google.gwt.user.client.ui.HasHorizontalAlignment;
import com.google.gwt.user.client.ui.HorizontalPanel;
import com.google.gwt.user.client.ui.Label;
import com.google.gwt.user.client.ui.ScrollPanel;
import com.google.gwt.user.client.ui.TextArea;
import com.google.gwt.user.client.ui.VerticalPanel;
import com.xlabs.client.DTO.QuestionDTO;
import com.xlabs.client.DTO.ReplyDTO;
import com.xlabs.client.richtext.ImageButton;

/**
 * Conversation view class.
 */
public class Conversation extends Composite
{
	/**
	 * Number of responses to show in one page of conversation.
	 */
	private static final int CONVERSATION_PAGESIZE = 10;

	/**
	 * ConversationPanel.
	 */
	private VerticalPanel conversationPanel = new VerticalPanel();

	/**
	 * Conversation scroll panel.
	 */
	private ScrollPanel conversationScroll = new ScrollPanel();
	
	/**
	 * Paging panel.
	 */
	private HorizontalPanel pagingPanel = new HorizontalPanel();
	
	/**
	 * Conversation grid.
	 */
	protected Grid conversationGrid = new Grid(CONVERSATION_PAGESIZE, 3);

	/**
	 * Corresponding question encoded key.
	 */
	private QuestionDTO questionDTO;

	/**
	 * Button to navigate to previous page of conversation.
	 */
	private ImageButton prevPageResponsesButton;

	/**
	 * Navigate button to next page of responses.
	 */
	private ImageButton nextPageRespnsesButton;

	/**
	 * Initializes Conversation. Wires the elements to elements and set the styles.
	 */
	public Conversation()
	{
		initWidget(conversationPanel);
		addStyleName("conversationPanel");
		conversationPanel.add(pagingPanel);
		conversationPanel.add(conversationScroll);
		conversationScroll.addStyleName("conversationScrollPanel");
		conversationGrid.addStyleName("conversationGrid");
		initPagingPanel();
	}
	

	/**
	 * Initializes paging panel.
	 */
	private void initPagingPanel() 
	{
		pagingPanel.addStyleName("pagingPanel");
		
        prevPageResponsesButton = new ImageButton(ImageConstants.PREVIOUS_PAGE_ICON_PNG, "");
        nextPageRespnsesButton = new ImageButton(ImageConstants.NEXT_PAGE_ICON_PNG, "");
        
        pagingPanel.setHorizontalAlignment(HasHorizontalAlignment.ALIGN_LEFT);
        prevPageResponsesButton.setUserStyleName(CSSConstants.PAGING_BUTTON);
        pagingPanel.add(prevPageResponsesButton);
        pagingPanel.setHorizontalAlignment(HasHorizontalAlignment.ALIGN_RIGHT);
        nextPageRespnsesButton.setUserStyleName(CSSConstants.PAGING_BUTTON);
        pagingPanel.add(nextPageRespnsesButton);
        
        prevPageResponsesButton.addClickHandler(new ClickHandler() 
        {
			public void onClick(ClickEvent event) 
			{
				queryPreviousPage();
			}
		});
        
        nextPageRespnsesButton.addClickHandler(new ClickHandler() 
        {
			public void onClick(ClickEvent event) 
			{
				queryNextPage();
			}
		});
	}

	/**
	 * Queries next page of responses.
	 */
	protected void queryNextPage()
	{
		// TODO Auto-generated method stub
		
	}


	/**
	 * Queries for previous page of responses.
	 */
	protected void queryPreviousPage()
	{
		// TODO Auto-generated method stub
		
	}


	/**
	 * Gets {@link #questionDTO}
	 * 
	 * @return {@link #questionDTO}
	 */
	public QuestionDTO getQuestionDTO()
	{
		return questionDTO;
	}

	/**
	 * Shows conversation for the given parent.
	 * 
	 * @param questionDTO
	 *            parent question's dto.
	 */
	public void showConversation(QuestionDTO questionDTO)
	{
		this.questionDTO = questionDTO;

		CommentingServiceAsync commentingService = (CommentingServiceAsync) GWT.create(CommentingService.class);
		
		commentingService.getConversation(
				questionDTO.getEncodedKey(),
				new ConversationAsyncCalBack(this));
	}

	/**
	 * Gets conversation scroll.
	 * 
	 * @return conversation scroll.
	 */
	public ScrollPanel getConversationScroll()
	{
		return conversationScroll;
	}

	/**
	 * Gets conversation grid.
	 * 
	 * @return conversation grid.
	 */
	public Grid getConversationGrid()
	{
		return conversationGrid;
	}

	/**
	 * Sets conversationGrid.
	 * 
	 * @param conversationGrid
	 *            Conversation grid.
	 */
	public void setConversationGrid(Grid conversationGrid)
	{
		conversationScroll.clear();
		conversationScroll.add(conversationGrid);
	}
}

/**
 * ConversationAsyncCalBack class.
 */
class ConversationAsyncCalBack implements AsyncCallback<List<ReplyDTO>>
{
	/**
	 * Corresponding conversation object.
	 */
	private Conversation conversation;

	public ConversationAsyncCalBack(Conversation conversation)
	{
		this.conversation = conversation;
	}

	/**
	 * On failure.
	 * 
	 * @param throwable
	 *            exception thrown by server.
	 */
	public void onFailure(Throwable throwable)
	{
		// To change body of implemented methods use File | Settings | File
		// Templates.
	}

	/**
	 * onSuccess.
	 * 
	 * @param replies
	 *            Object returned from server.
	 */
	public void onSuccess(List<ReplyDTO> replies)
	{
		Grid grid = populateConversationGrid(replies);

		conversation.setConversationGrid(grid);
	}

	/**
	 * Creates conversation grid and tree.
	 * 
	 * @param replies
	 *            replies received.
	 * @return grid created from the given replies.
	 */
	private Grid populateConversationGrid(List<ReplyDTO> replies)
	{
		Grid conversationGrid = conversation.getConversationGrid();
		int index = 0;

		for (ReplyDTO reply : replies)
		{

			if (reply.getParent() == null)
			{
				index = buildGrid(reply, conversationGrid, index, 0);
			}
		}

		return conversationGrid;
	}

	/**
	 * Appends the given reply to the given grid at the given index.
	 * 
	 * @param reply
	 *            Input reply.
	 * @param grid
	 *            Grid to add to.
	 * @param index
	 *            Where to add the reply in the grid.
	 * @param level
	 *            The level of reply in hierarchy.
	 * @return The index of last row inserted.
	 */
	private int buildGrid(ReplyDTO reply, Grid grid, int index, int level)
	{
		createGridRow(reply, grid, index, level);

		index++;

		for (ReplyDTO innerReply : reply.getReplies())
		{
			index = buildGrid(innerReply, grid, index, level + 1);
		}

		return index;
	}

	/**
	 * Creates row in the grid based on given reply at given index.
	 * 
	 * @param reply
	 *            Input reply.
	 * @param grid
	 *            Grid to add the row to.
	 * @param index
	 *            Index of row.
	 * @param level
	 *            The level of this reply in hierarchy.
	 */
	private void createGridRow(ReplyDTO reply, Grid grid, Integer index,
			int level)
	{
		String indentation = "";
		for (int i = 0; i < level; i++)
		{
			indentation = indentation + "...";
		}

		grid.setWidget(index, 0, new Label(indentation + reply.getReplyText()));

		Label userLabel = new Label(reply.getCreatedBy());
		grid.setWidget(index, 1, userLabel);

		ImageButton replyButton = new ImageButton("Email-Reply-icon.png", "");
		replyButton.addClickHandler(new InnerReplyClickHandler(index, grid,
				reply.getEncodedKey()));
		grid.setWidget(index, 2, replyButton);

		grid.getCellFormatter().addStyleName(index, 0, "GridCell");
		grid.getCellFormatter().addStyleName(index, 1, "GridCell");
		grid.getCellFormatter().addStyleName(index, 2, "GridCell");
	}

	/**
	 * ReplyListener class.
	 */
	private class InnerReplyClickHandler implements ClickHandler
	{

		/**
		 * index of reply.
		 */
		private int index;

		/**
		 * Comments grid.
		 */
		private Grid commentsGrid;

		/**
		 * Question key.
		 */
		private String parentReplyKey;

		/**
		 * Initializes an instance of ReplyListener.
		 * 
		 * @param index
		 *            index of row clicked.
		 * @param commentsGrid
		 *            The comments grid.
		 * @param parentReplyKey
		 *            key of the question.
		 */
		public InnerReplyClickHandler(int index, Grid commentsGrid,
				String parentReplyKey)
		{
			this.index = index;
			this.commentsGrid = commentsGrid;
			this.parentReplyKey = parentReplyKey;
		}

		/**
		 * Onclick.
		 * 
		 * @param widget
		 *            widget.
		 */
		public void onClick(ClickEvent event)
		{
			((ImageButton) event.getSource()).setVisible(false);
			Label commentLabel = (Label) commentsGrid.getWidget(index, 0);
			VerticalPanel replyBox = new VerticalPanel();
			
			replyBox.add(commentLabel);

			final TextArea replyArea = new TextArea();
			replyArea.setSize("300px", "100px");
			replyBox.add(replyArea);

			Button submitButton = new Button("Submit", new ClickHandler()
			{
				
				public void onClick(ClickEvent event)
				{
					((Button) event.getSource()).setEnabled(false);
					CommentingServiceAsync myService = (CommentingServiceAsync) GWT.create(CommentingService.class);
					
					myService.posInnertReply(
							replyArea.getText(),
							InnerReplyClickHandler.this.parentReplyKey,
							ConversationAsyncCalBack.this.conversation.getQuestionDTO().getEncodedKey(),
							new AsyncCallback<ReplyDTO>()
							{
		
								public void onFailure(Throwable throwable)
								{
									replyArea.setText("Failed to post Reply : "
											+ replyArea.getText()
											+ " Because of " + throwable);
								}
		
								public void onSuccess(ReplyDTO o)
								{
									replyArea.setText("Posted Reply : "
											+ replyArea.getText());
									replyArea.setReadOnly(true);
								}
							});
				}
			});

			replyBox.add(submitButton);
			commentsGrid.setWidget(index, 0, replyBox);
		}
	}
}
